﻿#include "FarFieldDataGenerator.h"
#include <vtkTable.h>
#include <vtkDataSet.h>
#include <vtkDoubleArray.h>
#include <vtkPointData.h>
#include <vtkStructuredGrid.h>
#include <vtkTableToStructuredGrid.h>
#include <vtkStructuredGridWriter.h>
#include <vtkCellDataToPointData.h>
#include <vtkTriangleFilter.h>
#include <vtkPolyDataNormals.h>
#include <vtkGeometryFilter.h>
#include <vtkPolyData.h>

#include <QDebug>
#include <QSet>
#include <vtkVariantArray.h>
#include <vtkDoubleArray.h>
#include <vtkDelimitedTextWriter.h>
#include <unordered_set>
#include "CommonFunction.h"

namespace pst
{

    FarFieldDataGenerator::FarFieldDataGenerator(QObject* parent)
        : QObject(parent), m_originalTable(vtkSmartPointer<vtkTable>::New()), m_logFactory(10), m_tableExtends{ 0, 0, 0 }
        //, m_originalTableColNumber{ 0 }
        //, m_originalTableRowNumber(0)
        ,
        m_errorInfo("")
    {
        m_devidedFreqencyTable.clear();
    }

    FarFieldDataGenerator::~FarFieldDataGenerator()
    {
    }

    void FarFieldDataGenerator::setInputData(vtkTable* table)
    {
        m_originalTable->DeepCopy(table);
        doThetaBias();
    }

    QList<double> FarFieldDataGenerator::getFreqencyList()
    {
        return m_freList;
    }

    QList<QString> FarFieldDataGenerator::getValueNameList()
    {
        return m_nameOfvalueList;
    }

    bool FarFieldDataGenerator::parseData(QString& errorInfo)
    {
        errorInfo = "";
        if (m_originalTable == nullptr)
        {
            errorInfo = "Error! The input table is null!";
            return false;
        }
        auto m_originalTableColNumber = m_originalTable->GetNumberOfColumns();
        auto m_originalTableRowNumber = m_originalTable->GetNumberOfRows();
        if (m_originalTableColNumber == 0 || m_originalTableRowNumber == 0)
        {
            errorInfo = "Error! The input table is empty!";
            return false;
        }
        if (m_originalTableRowNumber < 4)
        {
            errorInfo = "Error! The input table needs at least 4 columns! Current row count is " + m_originalTableRowNumber;
            return false;
        }

        auto FrequencyColumn = vtkDoubleArray::SafeDownCast(m_originalTable->GetColumn(0));
        if (FrequencyColumn == nullptr)
        {
            errorInfo = "Error! The input table needs a frequency column!";
            return false;
        }
        m_eachColNameOfKey.clear();
        m_eachColUnitOfKey.clear();
        m_eachColNameOfValue.clear();
        m_eachColUnitOfValue.clear();
        QList<QHash<int, QString>*> returnList;
        returnList << &m_eachColNameOfKey << &m_eachColUnitOfKey << &m_eachColNameOfValue << &m_eachColUnitOfValue;
        auto isOk = parseTitleName(m_originalTable, returnList, errorInfo);
        if (!isOk)
        {
            qDebug() << "Parse title name error: " << errorInfo;
            return false;
        }
        // 按频率分割表
        SplitVTKTable(m_originalTable);

        return true;
    }

    bool FarFieldDataGenerator::parseTitleName(vtkTable* inputTable,
        QList<QHash<int, QString>*>& returnList, QString& errorMessage)
    {
        if (returnList.size() != 4)
        {
            errorMessage = "Error! The input returnList needs 4 columns!";
            qDebug() << errorMessage;
            return false;
        }
        m_nameOfKeyList.clear();
        m_nameOfvalueList.clear();
        QHash<int, QString>& eachColNameOfKey = *returnList[0];
        QHash<int, QString>& eachColUnitOfKey = *returnList[1];
        QHash<int, QString>& eachColNameOfValue = *returnList[2];
        QHash<int, QString>& eachColUnitOfValue = *returnList[3];

        for (int i = 0; i < inputTable->GetNumberOfColumns(); ++i)
        {
            QString arrayName = QString(m_originalTable->GetColumn(i)->GetName()).trimmed();
            QStringList splitList = arrayName.split("||", QString::SkipEmptyParts);
            // auto arrayName = CommonFunction::trim(inputTable->GetColumn(i)->GetName());
            // std::vector<std::string> tempRes;
            // CommonFunction::Stringsplit(arrayName, "||", tempRes);
            if (splitList.size() != 3)
            {
                errorMessage = "File format illegal：" + arrayName;
                qDebug() << errorMessage;
                return false;
            }

            // 判断是key还是value
            QString type = splitList[2].trimmed();
            if (type.toUpper() == "KEY")
            {
                eachColNameOfKey[i] = splitList[0];
                eachColUnitOfKey[i] = splitList[1];
                m_nameOfKeyList.append(splitList[0]);
            }
            else if (type.toUpper() == "VALUE")
            {
                eachColNameOfValue[i] = splitList[0];
                eachColUnitOfValue[i] = splitList[1];
                m_nameOfvalueList.append(splitList[0]);
            }
            else
            {
                errorMessage = "File format illegal,neither 'key' nor 'value', type is " + type;
                qDebug() << errorMessage;
                return false;
            }
        }
        return true;
    }

    void FarFieldDataGenerator::FarFieldDataGenerator::doThetaBias()
    {
        if (m_originalTable == nullptr)
        {
            return;
        }

        auto colNum = m_originalTable->GetNumberOfColumns();
        auto rowNum = m_originalTable->GetNumberOfRows();

        auto thetaColumn = vtkDoubleArray::SafeDownCast(m_originalTable->GetColumn(1));
        if (thetaColumn == nullptr)
        {
            return;
        }

        for (int i = 0; i < rowNum; ++i)
        {
            thetaColumn->SetValue(i, 90 - thetaColumn->GetValue(i));
        }
    }

    bool FarFieldDataGenerator::getDataSetByFreqency(int freIndex, bool isLog,
        bool isNormalize, vtkPolyData* returnPointData, int valueIndex,
        QString& erorrMessage, vtkSmartPointer<vtkTable>& returnTable)
    {
        auto currentTable = m_devidedFreqencyTable.value(m_freList[freIndex]);
        if (currentTable == nullptr)
        {
            return false;
        }
        int _valueIndex = m_eachColNameOfKey.size() - 1 + valueIndex; // 去除频率列

        // 先归一化
        vtkSmartPointer<vtkTable> normalizedTable;
        if (isNormalize)
        {
            normalizedTable = vtkSmartPointer<vtkTable>::New();
            normalizeTheTable(currentTable, normalizedTable, _valueIndex);
        }
        else
        {
            normalizedTable = currentTable;
        }

        // 再取对数
        double colorOffeset{ 0 };
        vtkSmartPointer<vtkTable> resultTable;
        if (isLog)
        {
            decideLogCoefficients();
            resultTable = vtkSmartPointer<vtkTable>::New();
            logTheTable(normalizedTable, resultTable, colorOffeset, _valueIndex);
        }
        else
        {
            resultTable = normalizedTable;
        }

        vtkNew<vtkTable> transformedTLogTable;
        auto suc = transformRCSTableToFourColumnsRectangularTable(resultTable, transformedTLogTable, colorOffeset, _valueIndex);

        // #ifdef _DEBUG
        //         vtkNew<vtkDelimitedTextWriter> writer;
        //
        //         qDebug() << "m_devidedFreqencyTable.value(i) = ";
        //         QString name = "D:/transformedTLogTable.txt";
        //         writer->SetFileName(name.toStdString().c_str());
        //         writer->SetInputData(transformedTLogTable);
        //         writer->Write();
        // #endif

        if (!suc)
        {
            return false;
        }
        // qDebug() << "transformedTLogTable = ";
        // transformedTLogTable->Print(std::cout);
        computeTableExtends(currentTable);
        transformTableToStructuredGrid(transformedTLogTable, returnPointData, m_tableExtends[0] - 1, m_tableExtends[1] - 1, m_tableExtends[2] - 1);
        returnPointData->GetPointData()->SetActiveAttribute(0, vtkDataSetAttributes::AttributeTypes::SCALARS);
        returnTable = resultTable;

        return true;
    }

    void FarFieldDataGenerator::computeTableExtends(vtkTable* table)
    {
        if (table == nullptr)
        {
            return;
        }
        vtkIdType numberOfColumns = table->GetNumberOfColumns();
        if (numberOfColumns < 3)
        {
            return;
        }

        for (vtkIdType col = 0; col < numberOfColumns; ++col)
        {
            vtkDataArray* columnData = vtkDataArray::SafeDownCast(table->GetColumn(col));

            if (columnData && columnData->GetNumberOfValues() > 0)
            {
                std::unordered_set<double> uniqueValues;
                for (vtkIdType row = 0; row < columnData->GetNumberOfValues(); ++row)
                {
                    double value = columnData->GetComponent(row, 0);
                    uniqueValues.insert(value);
                }
                if (col < 2) // 只取theta和phi
                {
                    m_tableExtends[col] = uniqueValues.size();
                }
                //qDebug() << "Column " << col << " has " << uniqueValues.size() << " unique values.";
            }
            else
            {
                qDebug() << "Column " << col << " has no data.";
            }
        }
        m_tableExtends[2] = 1;
    }

    //void FarFieldDataGenerator::SetLogCoefficients(double factory)
    //{
    //    m_logFactory = factory;
    //}

    bool FarFieldDataGenerator::transformRCSTableToFourColumnsRectangularTable(
        vtkTable* inputTable, vtkTable* outputTable, double corlorOffset, int valueIndex)
    {
        vtkNew<vtkDoubleArray> arrX_Theta;
        vtkNew<vtkDoubleArray> arrY_Phi;
        vtkNew<vtkDoubleArray> arrZ_R;
        vtkNew<vtkDoubleArray> arrColor;
        arrX_Theta->SetName("X");
        arrY_Phi->SetName("Y");
        arrZ_R->SetName("Z");
        arrColor->SetName("Color");

        double r = 0.;
        double theta = 0.;
        double phi = 0.;
        constexpr double my_pi = 3.141592653589793238462643383279502884;
        constexpr double val = my_pi / 180;

        auto thetaArray = inputTable->GetColumn(0);
        auto phiArray = inputTable->GetColumn(1);
        auto rArray = inputTable->GetColumn(valueIndex);

        auto rowsNum = thetaArray->GetNumberOfTuples();

        double max = VTK_DOUBLE_MIN;
        double min = VTK_DOUBLE_MAX;
        for (int i = 0; i < rowsNum; ++i)//找出最小值，处理负数和0的情况
        {
            r = rArray->GetVariantValue(i).ToDouble();
            if (r > max)
            {
                max = r;
            }
            if (r < min)
            {
                min = r;
            }
        }

        if (min < 0.)
        {
            for (int i = 0; i < rowsNum; ++i)
            {
                theta = thetaArray->GetVariantValue(i).ToDouble() * val;
                phi = phiArray->GetVariantValue(i).ToDouble() * val;
                r = rArray->GetVariantValue(i).ToDouble() - min;//使r非负
                double color = rArray->GetVariantValue(i).ToDouble();

                // 将球坐标转为直角坐标
                arrX_Theta->InsertNextValue(r * std::sin(theta) * std::cos(phi));
                arrY_Phi->InsertNextValue(r * std::sin(theta) * std::sin(phi));
                arrZ_R->InsertNextValue(r * std::cos(theta));
                arrColor->InsertNextValue(color + corlorOffset);
            }
        }
        else
        {
            for (int i = 0; i < rowsNum; ++i)
            {
                theta = thetaArray->GetVariantValue(i).ToDouble() * val;
                phi = phiArray->GetVariantValue(i).ToDouble() * val;
                r = rArray->GetVariantValue(i).ToDouble();

                // 将球坐标转为直角坐标
                arrX_Theta->InsertNextValue(r * std::sin(theta) * std::cos(phi));
                arrY_Phi->InsertNextValue(r * std::sin(theta) * std::sin(phi));
                arrZ_R->InsertNextValue(r * std::cos(theta));
                arrColor->InsertNextValue(r + corlorOffset);
            }
        }

        // 保证多次调用每次传出去的表不会增加重复内容
        vtkNew<vtkTable> tempTable;
        tempTable->AddColumn(arrX_Theta);
        tempTable->AddColumn(arrY_Phi);
        tempTable->AddColumn(arrZ_R);
        tempTable->AddColumn(arrColor);
        outputTable->DeepCopy(tempTable);

        return true;
    }

    void FarFieldDataGenerator::transformTableToStructuredGrid(
        vtkTable* inputTable, vtkPolyData* outStructuredGrid, int xMax, int yMax, int zMax)
    {
        vtkNew<vtkTableToStructuredGrid> tableToSGFilter;
        tableToSGFilter->SetInputData(inputTable);
        tableToSGFilter->SetXColumn(inputTable->GetColumn(0)->GetName());
        tableToSGFilter->SetYColumn(inputTable->GetColumn(1)->GetName());
        tableToSGFilter->SetZColumn(inputTable->GetColumn(2)->GetName());
        tableToSGFilter->SetWholeExtent(0, xMax, 0, yMax, 0, zMax);

        tableToSGFilter->Update();

        // vtkNew< vtkStructuredGridWriter> writer;
        // writer->SetInputConnection(tableToSGFilter->GetOutputPort());
        // QString fileName = "D:/FarField" + QString::number(count) + ".vtk";
        // writer->SetFileName(fileName.toStdString().c_str());
        // writer->Write();

        auto geom = vtkSmartPointer<vtkGeometryFilter>::New();
        geom->SetInputConnection(tableToSGFilter->GetOutputPort());
        geom->Update();

        auto cell2pt = vtkSmartPointer<vtkCellDataToPointData>::New();
        cell2pt->SetInputData(geom->GetOutput());
        cell2pt->PassCellDataOff();
        cell2pt->Update();

        auto triFilter = vtkSmartPointer<vtkTriangleFilter>::New();
        //auto smoother = vtkSmartPointer<vtkWindowedSincPolyDataFilter>::New();
        auto normals = vtkSmartPointer<vtkPolyDataNormals>::New();

        //// 2. 三角化
        //triFilter->SetInputConnection(cell2pt->GetOutputPort());
        //triFilter->Update();

        // 3. 平滑
        //smoother->SetInputConnection(triFilter->GetOutputPort());
        //smoother->SetNumberOfIterations(15);
        //smoother->Update();


        // 4. 法线
        normals->SetInputConnection(cell2pt->GetOutputPort());
        normals->ComputePointNormalsOn();
        normals->Update();

        outStructuredGrid->DeepCopy(normals->GetOutput());
    }

    void FarFieldDataGenerator::logTheTable(vtkTable* inputTable,
        vtkTable* outputTable, double& logedMinimalValue, int valueIndex)
    {
        auto rowsNum = inputTable->GetNumberOfRows();
        auto colsNum = inputTable->GetNumberOfColumns();

        outputTable->DeepCopy(inputTable);

        auto valueArray = vtkDoubleArray::SafeDownCast(outputTable->GetColumn(valueIndex));

        double minValue = valueArray->GetValue(0);

        // 遍历所有值，寻找最小值和最大值
        for (vtkIdType i = 1; i < valueArray->GetNumberOfValues(); ++i)
        {
            double value = valueArray->GetValue(i);
            if (value < minValue)
                minValue = value;
        }

        // 第一列为Theta
        // 平移，使最小值为0，保证r具有物理意义，为到球坐标系原点的距离
        const double fac = 0.00000001;

        if (std::abs(minValue) < fac) // 存在0
        {
            for (vtkIdType i = 0; i < valueArray->GetNumberOfValues(); ++i)
            {
                auto value = valueArray->GetValue(i);
                valueArray->SetValue(i, m_logFactory * std::log10(value + fac) - m_logFactory * std::log10(minValue + fac));
            }
            logedMinimalValue = m_logFactory * std::log10(minValue + fac);
        }
        else
        {
            for (vtkIdType i = 0; i < valueArray->GetNumberOfValues(); ++i)
            {
                auto value = valueArray->GetValue(i);
                valueArray->SetValue(i, m_logFactory * std::log10(value) - m_logFactory * std::log10(minValue));
            }
            logedMinimalValue = m_logFactory * std::log10(minValue);
        }
    }

    void FarFieldDataGenerator::normalizeTheTable(vtkTable* inputTable, vtkTable* outputTable, int valueIndex)
    {
        auto rowsNum = inputTable->GetNumberOfRows();
        auto colsNum = inputTable->GetNumberOfColumns();

        if (valueIndex > colsNum - 1)
        {
            qDebug() << "Error! The valueIndex is out of range!";
            return;
        }

        outputTable->DeepCopy(inputTable);
        auto valueArray = vtkDoubleArray::SafeDownCast(outputTable->GetColumn(valueIndex));

        double maxVal = 0.;
        //// 获取最大值
        for (int j = 0; j < rowsNum; ++j)
        {
            if (std::abs(valueArray->GetValue(j)) > maxVal)
            {
                maxVal = std::abs(valueArray->GetValue(j));
            }
        }

        for (int j = 0; j < rowsNum; ++j)
        {
            auto value = valueArray->GetValue(j);
            valueArray->SetValue(j, value / maxVal);
        }
    }

    // 按第0列数据分组
    void FarFieldDataGenerator::SplitVTKTable(vtkSmartPointer<vtkTable> inputTable)
    {
        m_freList.clear();
        m_devidedFreqencyTable.clear();

        vtkIdType numRows = inputTable->GetNumberOfRows();
        vtkIdType numCols = inputTable->GetNumberOfColumns();

        for (vtkIdType row = 0; row < numRows; row++)
        {
            double key = inputTable->GetValue(row, 0).ToDouble();
            if (m_devidedFreqencyTable.find(key) == m_devidedFreqencyTable.end())
            {
                vtkNew<vtkTable> newTable;
                // 不要频率列 //循环有问题
                for (vtkIdType col = 1; col < numCols; col++)
                {
                    vtkNew<vtkDoubleArray> newColumn;
                    newColumn->SetName(inputTable->GetColumnName(col));
                    newTable->AddColumn(newColumn);
                }
                m_devidedFreqencyTable[key] = newTable;
                m_freList.append(key);
            }

            auto table = m_devidedFreqencyTable[key];
            vtkNew<vtkVariantArray> rowData;
            for (vtkIdType col = 1; col < numCols; col++)
            {
                auto value = inputTable->GetValue(row, col);
                rowData->InsertNextValue(value);
            }
            table->InsertNextRow(rowData);

            //复制场数据，如注释
            table->GetFieldData()->DeepCopy(inputTable->GetFieldData());

            //qDebug() << "--------";
            //table->Print(std::cout);
        }

        // #ifdef _DEBUG
        //         vtkNew<vtkDelimitedTextWriter> writer;
        //         for (auto i : m_devidedFreqencyTable)
        //         {
        //             qDebug() << "m_devidedFreqencyTable.value(i) = ";
        //             i->Print(std::cout);
        //             QString fre = "D:/" + QString::number(m_devidedFreqencyTable.key(i)) + ".txt";
        //             writer->SetFileName(fre.toStdString().c_str());
        //             writer->SetInputData(i);
        //             writer->Write();
        //         }
        // #endif
    }

    void FarFieldDataGenerator::setFileDealType(int type)
    {
        m_fileDealType = type;
    }

    int FarFieldDataGenerator::getFileDealType()
    {
        return m_fileDealType;
    }

    void FarFieldDataGenerator::decideLogCoefficients()
    {
        //增益（7）人体吸收比（13）功率（16）方向性系数（17）雷达散射截面（18）
        QList<int> log10TypeList{ 7, 13, 16, 17, 18 };
        if (log10TypeList.contains(m_fileDealType))
        {
            m_logFactory = 10;
        }
        else
        {
            m_logFactory = 20;
        }
    }
} // namespace pst
